babl: refactor code to get rid of more branches in babl_process
authorØyvind Kolås <pippin@gimp.org>
Sun, 14 Jan 2018 21:49:40 +0000 (22:49 +0100)
committerØyvind Kolås <pippin@gimp.org>
Sun, 14 Jan 2018 22:30:11 +0000 (23:30 +0100)
In the best case scenario now, babl_process increments instrumentation
counters and directly calls the relevant registered fast path function,
with no additional call stack frames in-between.

babl/babl-fish-path.c
babl/babl-fish-reference.c
babl/babl-fish-simple.c
babl/babl-fish.c
babl/babl-fish.h
babl/babl-internal.h

index dbfa4de2f07614785bc3ab75f32d4bdc75b0a461..301dd5c382427bdeff17d8559454a7c73d68d192 100644 (file)
@@ -596,12 +596,8 @@ babl_fish_path2 (const Babl *source,
       return NULL;
     }
 
-  if (babl_list_size (babl->fish_path.conversion_list) == 1)
-    {
-      babl->class_type = BABL_FISH_SIMPLE;
-      babl->fish_simple.conversion = (void*)babl_list_get_first (babl->fish_path.conversion_list);
-    }
-
+  babl_fish_prepare_bpp (babl);
+  _babl_fish_rig_dispatch (babl);
   /* Since there is not an already registered instance by the required
    * name, inserting newly created class into database.
    */
@@ -610,7 +606,6 @@ babl_fish_path2 (const Babl *source,
     babl_db_insert (babl_fish_db (), babl);
   }
   babl_mutex_unlock (babl_format_mutex);
-  babl_fish_prepare_bpp (babl);
   return babl;
 }
 
@@ -648,9 +643,10 @@ babl_fish_path (const Babl *source,
 
 static inline void
 babl_fish_path_process (const Babl *babl,
-                        const void *source,
-                        void       *destination,
-                        long        n)
+                        const char *source,
+                        char       *destination,
+                        long        n,
+                        void       *data)
 {
   process_conversion_path (babl->fish_path.conversion_list,
                            source,
@@ -660,34 +656,40 @@ babl_fish_path_process (const Babl *babl,
                            n);
 }
 
-static long
-_babl_process (Babl *babl,
-               const void *source,
-               void       *destination,
-               long        n)
+static inline void
+babl_fish_memcpy_process (const Babl *babl,
+                          const char *source,
+                          char       *destination,
+                          long        n,
+                          void       *data)
+{
+  memcpy (destination, source, n * babl->fish.source->format.bytes_per_pixel);
+}
+
+void
+_babl_fish_rig_dispatch (Babl *babl)
 {
   switch (babl->class_type)
     {
       case BABL_FISH_REFERENCE:
-        babl->fish.processings++;
-        babl->fish.pixels += n;
         if (babl->fish.source == babl->fish.destination)
-          { /* XXX: we're assuming linear buffers */
-            memcpy (destination, source, n * babl->fish.source->format.bytes_per_pixel);
+          {
+            babl->fish.dispatch = babl_fish_memcpy_process;
           }
         else
           {
-            babl_fish_reference_process (babl, source, destination, n);
+            babl->fish.dispatch = babl_fish_reference_process;
           }
         break;
 
       case BABL_FISH_SIMPLE:
-        babl->fish.processings++;
-        babl->fish.pixels += n;
         if (BABL (babl->fish_simple.conversion)->class_type == BABL_CONVERSION_LINEAR)
           {
-            babl_conversion_process (BABL (babl->fish_simple.conversion),
-                                     source, destination, n);
+            /* lift out conversion from single step conversion and make it be the dispatch function
+             * itself
+             */
+            babl->fish.data = babl->fish_simple.conversion->data;
+            babl->fish.dispatch = babl->fish_simple.conversion->dispatch;
           }
         else
           {
@@ -696,9 +698,19 @@ _babl_process (Babl *babl,
         break;
 
       case BABL_FISH_PATH:
-        babl->fish.processings++;
-        babl->fish.pixels += n;
-        babl_fish_path_process (babl, source, destination, n);
+        if (babl_list_size(babl->fish_path.conversion_list) == 1)
+        {
+          BablConversion *conversion = (void*)babl_list_get_first(babl->fish_path.conversion_list);
+
+          /* do same short-circuit optimization as for simple fishes */
+
+          babl->fish.dispatch = conversion->dispatch;
+          babl->fish.data     = conversion->data;
+        }
+        else
+        {
+          babl->fish.dispatch = babl_fish_path_process;
+        }
         break;
 
       case BABL_CONVERSION:
@@ -706,14 +718,24 @@ _babl_process (Babl *babl,
       case BABL_CONVERSION_PLANE:
       case BABL_CONVERSION_PLANAR:
         babl_assert (0);
-        babl_conversion_process (babl, source, destination, n);
         break;
 
       default:
         babl_log ("NYI");
-        return -1;
         break;
     }
+}
+
+static long
+_babl_process (const Babl *cbabl,
+               const void *source,
+               void       *destination,
+               long        n)
+{
+  Babl *babl = (void*)cbabl;
+  babl->fish.processings++;
+  babl->fish.pixels += n;
+  babl->fish.dispatch (babl, source, destination, n, babl->fish.data);
   return n;
 }
 
@@ -745,33 +767,16 @@ babl_process_rows (const Babl *fish,
   if (n <= 0)
     return 0;
 
-  /* first check if it is a fish since that is our fast path */
-  if (babl->class_type >= BABL_FISH &&
-      babl->class_type <= BABL_FISH_PATH)
+  babl->fish.processings++;
+  babl->fish.pixels += n * rows;
+  for (row = 0; row < rows; row++)
     {
-      babl->fish.processings++;
-      babl->fish.pixels += n * rows;
-      for (row = 0; row < rows; row++)
-        {
-          _babl_process ((void*)babl, src, dst, n);
-          src += source_stride;
-          dst += dest_stride;
-        }
-      return n * rows;
-    }
+      babl->fish.dispatch (babl, (void*)src, (void*)dst, n, babl->fish.data);
 
-  /* matches all conversion classes */
-  if (babl->class_type >= BABL_CONVERSION &&
-      babl->class_type <= BABL_CONVERSION_PLANAR)
-  {
-    for (row = 0; row < rows; row++)
-    {
-      babl_conversion_process (babl, (void*)src, (void*)dst, n);
       src += source_stride;
       dst += dest_stride;
     }
-    return n * rows;
-  }
+  return n * rows;
 
   babl_fatal ("eek");
   return -1;
@@ -894,8 +899,8 @@ init_path_instrumentation (FishPathInstrumentation *fpi,
                                              fpi->fmt_rgba_double->format.bytes_per_pixel);
 
   /* create sourcebuffer from testbuffer in the correct format */
-  babl_process (fpi->fish_rgba_to_source,
-                test_pixels, fpi->source, fpi->num_test_pixels);
+  _babl_process (fpi->fish_rgba_to_source,
+                 test_pixels, fpi->source, fpi->num_test_pixels);
 
   /* calculate the reference buffer of how it should be */
   ticks_start = babl_ticks ();
@@ -905,8 +910,8 @@ init_path_instrumentation (FishPathInstrumentation *fpi,
   fpi->reference_cost = ticks_end - ticks_start;
 
   /* transform the reference destination buffer to RGBA */
-  babl_process (fpi->fish_destination_to_rgba,
-                fpi->ref_destination, fpi->ref_destination_rgba_double, fpi->num_test_pixels);
+  _babl_process (fpi->fish_destination_to_rgba,
+                 fpi->ref_destination, fpi->ref_destination_rgba_double, fpi->num_test_pixels);
 }
 
 static void
@@ -983,8 +988,8 @@ get_path_instrumentation (FishPathInstrumentation *fpi,
   /* transform the reference and the actual destination buffers to RGBA
    * for comparison with each other
    */
-  babl_process (fpi->fish_destination_to_rgba,
-                fpi->destination, fpi->destination_rgba_double, fpi->num_test_pixels);
+  _babl_process (fpi->fish_destination_to_rgba,
+                 fpi->destination, fpi->destination_rgba_double, fpi->num_test_pixels);
 
   *path_error = babl_rel_avg_error (fpi->destination_rgba_double,
                                     fpi->ref_destination_rgba_double,
index 072c10fb261fee80362b555f625ea01948d1777b..695c3ca771bedbe616b2b231eeb710220982e070 100644 (file)
@@ -115,6 +115,7 @@ babl_fish_reference (const Babl *source,
 #ifndef HAVE_TLS
       free (name);
 #endif
+      _babl_fish_rig_dispatch (babl);
       return babl;
     }
 
@@ -124,7 +125,7 @@ babl_fish_reference (const Babl *source,
   babl_assert (source->class_type == BABL_FORMAT);
   babl_assert (destination->class_type == BABL_FORMAT);
 
-  babl = babl_malloc (sizeof (BablFishReference) +
+  babl = babl_calloc (1, sizeof (BablFishReference) +
                       strlen (name) + 1);
   babl->class_type    = BABL_FISH_REFERENCE;
   babl->instance.id   = babl_fish_get_id (source, destination);
@@ -138,6 +139,7 @@ babl_fish_reference (const Babl *source,
   babl->fish.error       = 0.0;  /* assuming the provided reference conversions for types
                                     and models are as exact as possible
                                   */
+  _babl_fish_rig_dispatch (babl);
 
   /* Since there is not an already registered instance by the required
    * name, inserting newly created class into database.
@@ -443,7 +445,8 @@ void
 babl_fish_reference_process (const Babl *babl,
                              const char *source,
                              char       *destination,
-                             long        n)
+                             long        n,
+                             void       *data)
 {
   void *source_double_buf;
   void *rgba_double_buf;
index eeaed519caaf37022aff4a6d62719789ecdae407..1fa338416e2846bfc28b7e190c06e4a043e146de 100644 (file)
@@ -42,7 +42,7 @@ babl_fish_simple (BablConversion *conversion)
       return babl;
     }
 
-  babl = babl_malloc (sizeof (BablFishSimple) +
+  babl = babl_calloc (1, sizeof (BablFishSimple) +
                       strlen (name) + 1);
   babl->class_type    = BABL_FISH_SIMPLE;
   babl->instance.id   = babl_fish_get_id (conversion->source, conversion->destination);
@@ -58,6 +58,7 @@ babl_fish_simple (BablConversion *conversion)
                                    reference, and babl fish reference only requests clean
                                    conversions */
 
+  _babl_fish_rig_dispatch (babl);
   /* Since there is not an already registered instance by the required
    * name, inserting newly created class into database.
    */
index 749b075c2930ec74fb33482677a66594d2de72de..8c73a2bb1bec730063c4c0247733a6424554eaa8 100644 (file)
@@ -257,6 +257,7 @@ babl_fish (const void *source,
         if (ffish.fish_path)
           {
             /* we have found suitable fish path in the database */
+            _babl_fish_rig_dispatch (ffish.fish_path);
             return ffish.fish_path;
           }
 
index 9f0cdd657309f89029967a0e8ecf0dee3d159bb8..36ef0989d705731fd68e18680d27883908dda2ed 100644 (file)
@@ -31,7 +31,7 @@ typedef struct
   BablInstance    instance;
   const Babl     *source;
   const Babl     *destination;
-  void           (*dispatch) (const Babl *babl, const char *src, char *dst, long n);
+  void           (*dispatch) (const Babl *babl, const char *src, char *dst, long n, void *data);
   void            *data;  /* user data */
   double          error;    /* the amount of noise introduced by the fish */
 
index 337541bfc2528a8067f32fccb75d5c2f4179cf22..9d29b47dc8370b04fa9593e810391a8a07c5eb3d 100644 (file)
@@ -78,7 +78,8 @@ void     babl_extension_deinit          (void);
 void     babl_fish_reference_process    (const Babl *babl,
                                          const char *source,
                                          char       *destination,
-                                         long        n);
+                                         long        n,
+                                         void       *data); // data is ignored
 
 Babl   * babl_fish_reference            (const Babl     *source,
                                          const Babl     *destination);
@@ -495,4 +496,6 @@ babl_conversion_process (const Babl *babl,
   conversion->dispatch (babl, source, destination, n, conversion->data);
 }
 
+void _babl_fish_rig_dispatch (Babl *babl);
+
 #endif